package com.amkai.aes.webservice.binary.objecthandler.billing;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.amkai.aes.aescommon.factory.RADBeanFactory;
import com.amkai.aes.aescommon.ledger.managers.AllocationManager;
import com.amkai.aes.aescommon.ledger.managers.BaseAmountManager;
import com.amkai.aes.aescommon.ledger.managers.ChargeManager;
import com.amkai.aes.aescommon.ledger.managers.CorrectionManager;
import com.amkai.aes.aescommon.ledger.managers.EntryManager;
import com.amkai.aes.aescommon.ledger.managers.PaymentManager;
import com.amkai.aes.aescommon.ledger.managers.details.FromToManager;
import com.amkai.aes.aescommon.ledger.utils.AllocationPairUtils;
import com.amkai.aes.aescommon.ledger.utils.ChargeUtils;
import com.amkai.aes.aescommon.ledger.utils.CorrectionUtils;
import com.amkai.aes.aescommon.service.binary.job.billing.TransferToBgJob;
import com.amkai.aes.generatedbeans.billinggroup.BillingGroup;
import com.amkai.aes.generatedbeans.billinggroup.BillingGroupInsurance;
import com.amkai.aes.generatedbeans.billinginterval.Batch;
import com.amkai.aes.generatedbeans.billingledger.Allocation;
import com.amkai.aes.generatedbeans.billingledger.Amount;
import com.amkai.aes.generatedbeans.billingledger.AnesthesiaChargeCalculation;
import com.amkai.aes.generatedbeans.billingledger.Charge;
import com.amkai.aes.generatedbeans.billingledger.ChargeAdditionalInformation;
import com.amkai.aes.generatedbeans.billingledger.ChargeDiagnosisAssociation;
import com.amkai.aes.generatedbeans.billingledger.Correction;
import com.amkai.aes.generatedbeans.billingledger.Debit;
import com.amkai.aes.generatedbeans.billingledger.Entry;
import com.amkai.aes.generatedbeans.billingledger.JournalCodeTransactionKind;
import com.amkai.aes.generatedbeans.billingledger.Payment;
import com.amkai.aes.generatedbeans.billingledger.TransactionKind;
import com.amkai.aes.generatedbeans.billingledger.TransactionType;
import com.amkai.aes.generatedbeans.billingledger.UB0481CCLine;
import com.amkai.aes.generatedbeans.billingledger.UnassignedPayment;
import com.amkai.aes.generatedbeans.billingledger.WriteOff;
import com.amkai.aes.generatedbeans.billingledger.additionalcodes.ConditionCode;
import com.amkai.aes.generatedbeans.billingledger.additionalcodes.NoteInformation;
import com.amkai.aes.generatedbeans.billingledger.additionalcodes.OccurrenceCodeDate;
import com.amkai.aes.generatedbeans.billingledger.additionalcodes.OccurrenceSpanCodeDate;
import com.amkai.aes.generatedbeans.billingledger.additionalcodes.SupplementalInformation;
import com.amkai.aes.generatedbeans.billingledger.additionalcodes.ValueCodeAmount;
import com.amkai.aes.generatedbeans.billingledger.billinggrouptransfer.BillingGroupSetup;
import com.amkai.aes.generatedbeans.billingledger.details.DenialCodePair;
import com.amkai.aes.generatedbeans.billingledger.details.FromTo;
import com.amkai.aes.generatedbeans.billingledger.details.JournalCode;
import com.amkai.aes.generatedbeans.common.DateInterval;
import com.amkai.aes.generatedbeans.insurance.InsurancePlan;
import com.amkai.aes.generatedbeans.organization.Department;
import com.amkai.aes.generatedbeans.passport.Passport;
import com.amkai.aes.generatedmodels.billing.transaction.TransactionDomain;
import com.amkai.aes.server.billing.ledger.LedgerManager;
import com.amkai.aes.server.billing.ledger.ServerLedgerEntryLoadManager;
import com.amkai.aes.server.domaincommiter.commiters.billing.ledger.TransactionDomainComitter;
import com.amkai.aes.server.manager.AbstractEntryCommitter;
import com.amkai.aes.server.session.ServiceSessionManager;
import com.amkai.common.base.utils.BeanManager;
import com.amkai.common.extensions.hibernate.config.manager.SessionManager;
import com.amkai.rad.designerbase.beans.ChangedKind;

public class TransferToBillingGroupManager {
	private static final Log log = LogFactory.getLog(TransferToBillingGroupManager.class);
	
	Charge originalCharge = null;
	Charge transferedCharge = null;
	Long chargeId = null;
	Long billingGroupId = null;
	Department department;
	SessionManager sm = null;
	String note = "Posted using the Transfer to BG option.";
	Passport owner;
	private BillingGroupSetup bgs;
	List<TransactionDomain> allocationsList = new ArrayList<TransactionDomain>();
	List<Entry> allocationCorrections = new ArrayList<Entry>();
	private Long batchId;
	private Batch newBatch;

	public TransferToBillingGroupManager(SessionManager sm, Department department, Long chargeId, Long billingGroupId, Long batchId) throws Exception {
		this.sm = sm;
		this.billingGroupId = billingGroupId;
		this.chargeId = chargeId;
		this.department = department;
		this.batchId = batchId;
		this.owner = sm.get(Passport.class, ServiceSessionManager.getConnection().getRuntimePassport().getId());

	}

	protected void processTransfer() throws Exception {
		sm.openTransaction();
		newBatch = sm.get(Batch.class, batchId);
		originalCharge = sm.get(Charge.class, chargeId);
		ServerLedgerEntryLoadManager.getChildEntries(originalCharge);
		originalCharge = (Charge) ServerLedgerEntryLoadManager.loadEntry(originalCharge, department, sm);
		// Not save new charge
		transferedCharge = transferCharge(originalCharge);
		// Process correction on "old" charge
		originalCharge = processCorrections(originalCharge);

		if (allocationCorrections.size() > 0) {
			//ServerLedgerEntrySaveManager slesm = ServerLedgerEntrySaveManager.initialize(department, sm);
			//slesm.saveEntries(allocationCorrections);
			LedgerManager.saveEntries(sm, allocationCorrections);
		}
		LedgerManager.saveEntry(sm, originalCharge);
		LedgerManager.saveEntry(sm, transferedCharge);
		sm.commitTransaction();
		for (TransactionDomain td : allocationsList) {
			td.getPayment().setParent(td.getCharge());
			td.getPayment().setRootEntry(td.getCharge());
			td.getCharge().getChildEntries().add(td.getPayment());
			// KKORNEL: AES-17594
			td.getCharge().getRootEntries().add(td.getPayment());
			td.getAllocation().setParent(td.getUnassignedPayment());
			td.getAllocation().setRootEntry(td.getUnassignedPayment());
			//ServerLedgerEntrySaveManager.savePaymentAllocation(td);
			TransactionDomainComitter.savePaymentAllocation(sm, td);
		}
		// SupplyLog prepare in copyCharge()
		prepareCDMCaseHistoryProcedureLog(sm, originalCharge, transferedCharge);
	}

	private void prepareCDMCaseHistoryProcedureLog(SessionManager sm2, Charge oCharge, Charge newCharge) {
		sm.execute("UPDATE ProcedureLog pl SET pl.charge = :nc WHERE pl.charge = :oc ").setEntity("nc", newCharge).setEntity("oc", oCharge).executeUpdate();

	}

	@SuppressWarnings("unchecked")
	private Charge processCorrections(Charge oCharge) throws Exception {
		BigDecimal due;
		CorrectionManager cm;
		
		for (Entry entry : oCharge.getChildEntries()) {
			if (entry.isIsActive()) {
				switch (entry.getTransactionKind()) {
				case CHARGE_DEBIT:
					// createCorrection
					due = BaseAmountManager.calculateDue((Debit) entry).abs();
					if (!due.equals(new BigDecimal(0.00).setScale(2))) {
						cm = CorrectionManager.createCorrection((Amount) entry, owner);
						cm.setBatch(newBatch);
						cm.setAmount(due);
						cm.setJournalCode(getBgs().getDebitCorrectionJournalCode());
						cm.setNote(note);
					}
					break;
				case PAYMENT:
					due = BaseAmountManager.calculateDue((Payment) entry).abs();
					if (!due.equals(new BigDecimal(0.00).setScale(2))) {
						cm = CorrectionManager.createCorrection((Amount) entry, owner);
						cm.setBatch(newBatch);
						cm.setAmount(due);
						cm.setJournalCode(getBgs().getPaymentCorrectionJournalCode());
						cm.setNote(note);
					}
					break;
				case WRITEOFF:
					due = BaseAmountManager.calculateDue((WriteOff) entry).abs();
					if (!due.equals(new BigDecimal(0.00).setScale(2))) {
						cm = CorrectionManager.createCorrection((Amount) entry, owner);
						cm.setBatch(newBatch);
						cm.setAmount(due);
						cm.setJournalCode(getBgs().getWriteoffCorrectionJournalCode());
						cm.setNote(note);
					}
					break;
				case PAYMENT_ALLOCATION:
					due = BaseAmountManager.calculateDue((Payment) entry).abs();
					if (!due.equals(new BigDecimal(0.00).setScale(2))) {
						// KKORNEL: AES-17594
						Correction correction = createCorrection(newBatch, owner, (Amount) entry, getBgs().getAllocationCorrectionJournalCode());
						correction.putTranzientProperty(AbstractEntryCommitter.NEW_ACTIVE_STATUS_KEY, Boolean.TRUE);
						allocationCorrections.add(correction);
					}
					break;
				default:
					break;
				}
			}
		}
		if (!oCharge.getDue().equals(new BigDecimal(0.00).setScale(2))) {
			due = BaseAmountManager.calculateDue(oCharge).abs();
			if (!due.equals(new BigDecimal(0.00).setScale(2))) {
				cm = CorrectionManager.createCorrection(oCharge, owner);
				cm.setBatch(newBatch);
				cm.setAmount(due);
				cm.setJournalCode(getBgs().getChargeCorrectionJournalCode());
				cm.setNote(note);
				cm.setActive(true);
			}
		}
		return oCharge;
	}

	public Correction createCorrection(Batch batch, Passport owner, Amount entry, JournalCode jc) {
		BigDecimal due = BaseAmountManager.calculateDue(entry).abs();
		Correction correction = (Correction) RADBeanFactory.getInstance().createEntry(CorrectionUtils.getCorrectionKind(entry.getTransactionKind()));
		correction.setParent(entry);
		correction.setRootEntry(entry.getRootEntry());
		entry.getChildEntries().add(correction);
		entry.getRootEntry().getRootEntries().add(correction);
		correction.setChangedKind(ChangedKind.CREATED);
		correction.getRootEntry().setChangedKind(ChangedKind.CHANGED);
		switch (correction.getTransactionKind()) {
		case CHARGE_DEBIT_CORRECTION:
		case ALLOCATION_PAYMENT_CORRECTION:
			correction.setType(TransactionType.CREDIT);
			break;
		default:
			correction.setType(TransactionType.DEBIT);
		}
		correction.setTransactionDate(Calendar.getInstance().getTime());
		correction.setAccount(correction.getParent().getAccount());
		correction.setPatient(correction.getParent().getPatient());
		correction.setBatch(batch);
		correction.setOwner(owner);
		correction.setCorrectionTo(entry);
		correction.setAmount(due);
		correction.setDue(due);
		correction.setJournalCode(jc);
		correction.setIsActive(true);
		entry.setChangedKind(ChangedKind.CHANGED);
		return correction;
	}

	private Charge transferCharge(Charge oCharge) throws Exception {
		BillingGroup bg = sm.get(BillingGroup.class, billingGroupId);
		Charge charge = (Charge) ChargeManager.createCharge(owner, oCharge.getPatient(), newBatch, bg, oCharge.getPmCase(), oCharge.getProvider()).getEntry();

		copyCharge(originalCharge, charge);
		// KKORNEL: AES-17487, AES-17502
		LedgerManager.saveEntry(sm, charge);
		//sm.saveRAD(charge);
		processTransactions(originalCharge, charge);

		LedgerManager.saveEntry(sm, charge);
		//sm.saveRAD(charge);
		return charge;
	}

	private void processTransactions(Charge oCharge, Charge charge) throws Exception {
		for (Entry entry : oCharge.getChildEntries()) {
			if (entry.isIsActive()) {
				switch (entry.getTransactionKind()) {
				case PAYMENT:
					createPayment((Payment) entry, charge);
					break;
				case WRITEOFF:
					createWriteOff((WriteOff) entry, charge);
					break;
				case CHARGE_DEBIT:
					createDebit((Debit) entry, charge);
					break;
				case PAYMENT_ALLOCATION:
					createAllocation((Payment) entry, charge);
					break;
				case CHARGE_CORRECTION:
					modifyChargeAmount((Correction) entry, charge);
					break;
				default:
					break;
				}
			}
		}

	}

	@SuppressWarnings("unchecked")
	private void createAllocation(Payment payment, Charge charge) throws Exception {

		BigDecimal due = BaseAmountManager.calculateDue(payment).abs();

		if (!due.equals(new BigDecimal(0.00).setScale(2))) {
			Entry upParent = (AllocationPairUtils.getPair(payment).getRootEntry());
			UnassignedPayment up = sm.get(UnassignedPayment.class, upParent.getId());

			AllocationManager am = null;
			am = AllocationManager.create(owner);
			am.setJournalCode(getBgs().getAllocationPostJournalCode());
			FromTo fromTo = FromToManager.clone(up.getFromEntry());
			sm.saveRAD(fromTo);
			am.setFromEntry(fromTo);
			am.setAccount(payment.getAccount());
			am.setPatient(payment.getPatient());
			am.setAmount(due);
			am.setBatch(newBatch);
			am.setLastEditDate(new Date());
			am.setLastEditor(owner);
			am.setParent(null);
			am.setTransactionDate(payment.getTransactionDate());
			am.setRootEntry(null);

			PaymentManager pm = (PaymentManager) EntryManager.createManager(TransactionKind.PAYMENT_ALLOCATION, owner);
			pm.setJournalCode(getBgs().getPaymentPostJournalCode());
			pm.setAccount(payment.getAccount());
			fromTo = FromToManager.clone(charge.getFromEntry());
			sm.saveRAD(fromTo);
			pm.setFromEntry(fromTo);
			pm.setAmount(due);
			pm.setTransactionDate(payment.getTransactionDate());
			pm.setPatient(payment.getPatient());
			pm.setBatch(newBatch);
			pm.setPaymentType(up.getPaymentType());
			pm.setLastEditDate(new Date());
			pm.setLastEditor(owner);
			pm.setTransactionDate(payment.getTransactionDate());
			pm.setParent(null);
			pm.setRootEntry(null);

			TransactionDomain td = new TransactionDomain();
			td.setCharge(charge);
			td.setUnassignedPayment(up);
			td.setAllocation((Allocation) am.getEntry());
			td.setPayment((Payment) pm.getEntry());
			td.setAllocateheader(new ArrayList<Charge>());
			td.getAllocateheader().add(charge);
			allocationsList.add(td);
		}

	}

	private void modifyChargeAmount(Correction correction, Charge charge) {
		charge.setAmount(charge.getAmount().subtract(correction.getAmount()));
	}

	private void createDebit(Debit debit, Charge charge) {
		BigDecimal due = BaseAmountManager.calculateDue(debit).abs();
		if (!due.equals(new BigDecimal(0.00).setScale(2))) {
			Debit newDebit = ChargeUtils.createDebit(charge, owner);
			newDebit.setAccount(debit.getAccount());
			newDebit.setAmount(due);
			newDebit.setBatch(newBatch);
			newDebit.setDue(due);
			newDebit.setEntryDate(new Date());
			sm.saveRAD(charge.getFromEntry());
			newDebit.setJournalCode(getJournalCode(JournalCodeTransactionKind.DEBIT, charge.getBillingGroup()));
			newDebit.setLastEditDate(new Date());
			newDebit.setLastEditor(owner);
			newDebit.setNote(getNote(debit.getNote()) );
			newDebit.setPrintOnStatement(debit.isPrintOnStatement());
			newDebit.setTransactionDate(debit.getTransactionDate());
		}
	}
	private String getNote(String originalNote){		
		return (originalNote == null || originalNote.isEmpty()) ? note : originalNote + " \n" + note; 
	}

	private void createWriteOff(WriteOff writeOff, Charge charge) {
		BigDecimal due = BaseAmountManager.calculateDue(writeOff).abs();
		if (!due.equals(new BigDecimal(0.00).setScale(2))) {
			WriteOff newWriteOff = ChargeUtils.createWriteOff(charge, owner);
			newWriteOff.setAccount(writeOff.getAccount());
			newWriteOff.setAmount(due);
			newWriteOff.setBatch(newBatch);
			newWriteOff.setDue(due);
			newWriteOff.setEntryDate(new Date());
			newWriteOff.setJournalCode(getJournalCode(JournalCodeTransactionKind.WRITEOFF, charge.getBillingGroup()));
			newWriteOff.setLastEditDate(new Date());
			newWriteOff.setLastEditor(owner);
			newWriteOff.setNote(getNote(writeOff.getNote()));
			newWriteOff.setPrintOnStatement(writeOff.isPrintOnStatement());
			newWriteOff.setTransactionDate(writeOff.getTransactionDate());
			if (writeOff.getDenialCodePair() != null) {
				DenialCodePair dcp = RADBeanFactory.getInstance().createBean(DenialCodePair.class);
				dcp.setGroupCode(writeOff.getDenialCodePair().getGroupCode());
				dcp.setReasonCode(writeOff.getDenialCodePair().getReasonCode());
				sm.saveRAD(dcp);
				newWriteOff.setDenialCodePair(dcp);
			}
		}
	}

	private void createPayment(Payment payment, Charge charge) throws Exception {
		BigDecimal due = BaseAmountManager.calculateDue(payment).abs();

		if (!due.equals(new BigDecimal(0.00).setScale(2))) {
			Payment newPayment = ChargeUtils.createPayment(charge, owner);
			newPayment.setAccount(payment.getAccount());
			newPayment.setAmount(due);
			newPayment.setBatch(newBatch);
			newPayment.setCheckNumber(payment.getCheckNumber());
			newPayment.setDue(due);
			newPayment.setEntryDate(new Date());
			newPayment.setFreePaymentText(payment.getFreePaymentText());
			newPayment.setFromEntry(FromToManager.clone(charge.getFromEntry()));
			newPayment.setJournalCode(getJournalCode(JournalCodeTransactionKind.PAYMENT, charge.getBillingGroup()));
			newPayment.setLastEditDate(new Date());
			newPayment.setLastEditor(owner);
			newPayment.setNote(getNote(payment.getNote()));
			newPayment.setPaymentType(payment.getPaymentType());
			newPayment.setPrintOnStatement(payment.isPrintOnStatement());
			newPayment.setTransactionDate(payment.getTransactionDate());
		}
	}

	private void copyCharge(Charge oCharge, Charge charge) throws Exception {

		charge.setAbstractAppointment(oCharge.getAbstractAppointment());
		charge.setAcceptAssignment(oCharge.getAcceptAssignment());
		charge.setAdjudicationDate(oCharge.getAdjudicationDate());
		charge.setAmount(oCharge.getAmount());
		if (oCharge.getAnesthesiaChargeCalculation() != null) {
			AnesthesiaChargeCalculation acc = RADBeanFactory.getInstance().createBean(AnesthesiaChargeCalculation.class);
			String[] exclude = { "charges", "changedKind" };
			BeanManager.copy(oCharge.getAnesthesiaChargeCalculation(), acc, exclude);

			sm.saveRAD(acc);

			charge.setAnesthesiaChargeCalculation(acc);
		}
		charge.setAnesthesiaServiceType(oCharge.getAnesthesiaServiceType());
		BillingGroupInsurance bgiPI = null;
		if (charge.getBillingGroup().getBillingGroupInsurances() != null && charge.getBillingGroup().getBillingGroupInsurances().size() > 0) {
			for (BillingGroupInsurance bgi : charge.getBillingGroup().getBillingGroupInsurances()) {
				if (bgiPI == null) {
					bgiPI = bgi;
				} else {
					bgiPI = bgiPI.getSequence() < bgi.getSequence() ? bgi : bgiPI;
				}
			}
			charge.setBillPG(bgiPI.getInsurancePolicy().getInsurancePlan().isBillPG());
		} else {
			charge.setBillPG(false);
		}

		sm.saveRAD(charge.getFromEntry());
		charge.setBodySide(oCharge.getBodySide());
		ChargeAdditionalInformation cad = RADBeanFactory.getInstance().createBean(ChargeAdditionalInformation.class);
		sm.saveRAD(cad);
		charge.setChargeAdditionalInformation(cad);
		createChargeAdditionalInformation(charge, oCharge);
		createChargeDiagnosisAssociation(charge, oCharge);
		// set Billing Group Transfer Charge;
		oCharge.setBillingGroupTransferCharge(charge);
		charge.setCopay(oCharge.getCopay());
		charge.setCptModifier_1(oCharge.getCptModifier_1());
		charge.setCptModifier_2(oCharge.getCptModifier_2());
		charge.setCptModifier_3(oCharge.getCptModifier_3());
		charge.setCptModifier_4(oCharge.getCptModifier_4());
		charge.setDue(oCharge.getDue());
		charge.setEntryDate(new Date());
		charge.setFacility(oCharge.getFacility());
		charge.setGenerateClaim(oCharge.getGenerateClaim());
		charge.setIcdProcedureCode1(oCharge.getIcdProcedureCode1());
		charge.setIcdProcedureCode2(oCharge.getIcdProcedureCode2());
		charge.setIcdProcedureCode3(oCharge.getIcdProcedureCode3());
		charge.setLastEditDate(new Date());
		charge.setLastEditor(ServiceSessionManager.getConnection().getRuntimePassport());

		charge.setNote(getNote(oCharge.getNote()));
		charge.setOriginalClaimReferenceNumber(oCharge.getOriginalClaimReferenceNumber());
		charge.setOwner(oCharge.getOwner());

		charge.setPatient(oCharge.getPatient());
		charge.setPatientAmountPaid(oCharge.getPatientAmountPaid());
		setPatientResponsibility(charge, oCharge);
		charge.setPmCase(oCharge.getPmCase());
		charge.setPrintOnStatement(oCharge.isPrintOnStatement());
		charge.setProcedure(oCharge.getProcedure());
//		setCaseHistory(charge, oCharge);
		charge.setProvider(oCharge.getProvider());
		charge.setRcmOption(oCharge.getRcmOption());

		charge.setReferringProvider(oCharge.getReferringProvider());

		charge.setResubmissionCode(oCharge.getResubmissionCode());
		charge.setRevenueCode(oCharge.getRevenueCode());

		charge.setSourceOfRevenue(oCharge.getSourceOfRevenue());
		charge.setSupervisingProvider(oCharge.getSupervisingProvider());
		charge.setSupplyResource(oCharge.getSupplyResource());
		charge.setTransactionDate(oCharge.getTransactionDate());
		charge.setTransactionDateThru(oCharge.getTransactionDateThru());
		charge.setTypeOfBill(oCharge.getTypeOfBill());
		charge.setUnits(oCharge.getUnits());
		charge.setLastTransferDate(new Date());
		// CDM SupplyLog prepare
		
		//AES-15781
		//charge.setSupplyLog(oCharge.getSupplyLog());
		//oCharge.setSupplyLog(null);
		//FIXME : 3.6 Changes
		/*
		for (ChargeCdmLogAssociation assoc : oCharge.getChargeCdmLogAssociations()) {
			assoc.setCharge(charge);
		}
		*/
	}
/*
	private void setCaseHistory(Charge charge, Charge oCharge) {
		for (ProcedureLog pl : oCharge.getProcedureLogs()) {
			pl.setCharge(charge);
			sm.saveRAD(pl);
		}
		for (SupplyLog sl : oCharge.getSupplyLogs()) {
			sl.setCharge(charge);
			sm.saveRAD(sl);
		}
	}
*/
	private void setPatientResponsibility(Charge charge, Charge oCharge) {
		switch (charge.getFromEntry().getKind()) {
		case PRIMARY_GUARANTOR:
		case SECONDARY_GUARANTOR:
			charge.setPatientResponsibility(new BigDecimal(0.00).setScale(2));
			break;
		default:
			charge.setPatientResponsibility(oCharge.getPatientResponsibility());
			break;
		}
	}

	private void createChargeDiagnosisAssociation(Charge charge, Charge oldCharge) {
		for (ChargeDiagnosisAssociation cda : oldCharge.getChargeDiagnosisAssociations()) {
			ChargeDiagnosisAssociation new_cda = RADBeanFactory.getInstance().createBean(ChargeDiagnosisAssociation.class);
			new_cda.setDiagnosis(cda.getDiagnosis());
			new_cda.setSequence(cda.getSequence());
			new_cda.setCharge(charge);
			// KKORNEL: AES-13961
			new_cda.setPresentOnAdmission(cda.getPresentOnAdmission());
			charge.getChargeDiagnosisAssociations().add(new_cda);
		}

	}

	private void createChargeAdditionalInformation(Charge charge, Charge oldCharge) {

		Set<ValueCodeAmount> valuesCodeAmounts = null;
		if (oldCharge.getChargeAdditionalInformation() != null) {
			if (oldCharge.getChargeAdditionalInformation().getValueCodeAmounts() != null) {
				valuesCodeAmounts = oldCharge.getChargeAdditionalInformation().getValueCodeAmounts();
				charge.getChargeAdditionalInformation().setValueCodeAmounts(new HashSet<ValueCodeAmount>());
				for (ValueCodeAmount vca : valuesCodeAmounts) {
					ValueCodeAmount vca_new = RADBeanFactory.getInstance().createBean(ValueCodeAmount.class);
					vca_new.setAmount(vca.getAmount());
					vca_new.setCode(vca.getCode());
					vca_new.setSequence(vca.getSequence());
					vca_new.setChargeAdditionalInformation(charge.getChargeAdditionalInformation());
					sm.saveRAD(vca_new);
					charge.getChargeAdditionalInformation().getValueCodeAmounts().add(vca_new);
				}
			}
		}
		Set<ConditionCode> conditionCodes = null;
		if (oldCharge.getChargeAdditionalInformation() != null) {
			if (oldCharge.getChargeAdditionalInformation().getConditionCodes() != null) {
				conditionCodes = oldCharge.getChargeAdditionalInformation().getConditionCodes();
				charge.getChargeAdditionalInformation().setConditionCodes(new HashSet<ConditionCode>());
				for (ConditionCode cc : conditionCodes) {
					ConditionCode cc_new = RADBeanFactory.getInstance().createBean(ConditionCode.class);
					cc_new.setCode(cc.getCode());
					cc_new.setSequence(cc.getSequence());
					cc_new.setChargeAdditionalInformation(charge.getChargeAdditionalInformation());
					sm.saveRAD(cc_new);
					charge.getChargeAdditionalInformation().getConditionCodes().add(cc_new);
				}
			}
		}
		Set<OccurrenceCodeDate> occuranceCodeDates = null;
		if (oldCharge.getChargeAdditionalInformation() != null) {
			if (oldCharge.getChargeAdditionalInformation().getOccurrenceCodeDates() != null) {
				occuranceCodeDates = oldCharge.getChargeAdditionalInformation().getOccurrenceCodeDates();
				charge.getChargeAdditionalInformation().setOccurrenceCodeDates(new HashSet<OccurrenceCodeDate>());
				for (OccurrenceCodeDate ocd : occuranceCodeDates) {
					OccurrenceCodeDate ocd_new = RADBeanFactory.getInstance().createBean(OccurrenceCodeDate.class);
					ocd_new.setCode(ocd.getCode());
					ocd_new.setSequence(ocd.getSequence());
					ocd_new.setDate(ocd.getDate());
					ocd_new.setChargeAdditionalInformation(charge.getChargeAdditionalInformation());
					sm.saveRAD(ocd_new);
					charge.getChargeAdditionalInformation().getOccurrenceCodeDates().add(ocd_new);
				}
			}
		}
		Set<OccurrenceSpanCodeDate> occurrenceSpanCodeDates = null;
		if (oldCharge.getChargeAdditionalInformation() != null) {
			if (oldCharge.getChargeAdditionalInformation().getOccurrenceSpanCodeDates() != null) {
				occurrenceSpanCodeDates = oldCharge.getChargeAdditionalInformation().getOccurrenceSpanCodeDates();
				charge.getChargeAdditionalInformation().setOccurrenceSpanCodeDates(new HashSet<OccurrenceSpanCodeDate>());
				for (OccurrenceSpanCodeDate oscd : occurrenceSpanCodeDates) {
					OccurrenceSpanCodeDate oscd_new = RADBeanFactory.getInstance().createBean(OccurrenceSpanCodeDate.class);
					oscd_new.setCode(oscd.getCode());
					oscd_new.setSequence(oscd.getSequence());
					oscd_new.setDateFrom(oscd.getDateFrom());
					oscd_new.setDateTo(oscd.getDateTo());
					oscd_new.setChargeAdditionalInformation(charge.getChargeAdditionalInformation());
					sm.saveRAD(oscd_new);
					charge.getChargeAdditionalInformation().getOccurrenceSpanCodeDates().add(oscd_new);
				}
			}
		}

		Set<SupplementalInformation> supplementalInformations = null;
		if (oldCharge.getChargeAdditionalInformation() != null) {
			if (oldCharge.getChargeAdditionalInformation().getSupplementalInformations() != null) {
				supplementalInformations = oldCharge.getChargeAdditionalInformation().getSupplementalInformations();
				charge.getChargeAdditionalInformation().setSupplementalInformations(new HashSet<SupplementalInformation>());
				for (SupplementalInformation si : supplementalInformations) {
					SupplementalInformation si_new = RADBeanFactory.getInstance().createBean(SupplementalInformation.class);
					si_new.setControlNumber(si.getControlNumber());
					si_new.setReportTypeCode(si.getReportTypeCode());
					si_new.setTransmissionCode(si.getTransmissionCode());
					si_new.setSequence(si.getSequence());
					si_new.setChargeAdditionalInformation(charge.getChargeAdditionalInformation());
					sm.saveRAD(si_new);
					charge.getChargeAdditionalInformation().getSupplementalInformations().add(si_new);
				}
			}
		}

		Set<NoteInformation> noteInformations = null;
		if (oldCharge.getChargeAdditionalInformation() != null) {
			if (oldCharge.getChargeAdditionalInformation().getNoteInformations() != null) {
				noteInformations = oldCharge.getChargeAdditionalInformation().getNoteInformations();
				charge.getChargeAdditionalInformation().setNoteInformations(new HashSet<NoteInformation>());
				for (NoteInformation ni : noteInformations) {
					NoteInformation ni_new = RADBeanFactory.getInstance().createBean(NoteInformation.class);
					ni_new.setNoteReferenceCode(ni.getNoteReferenceCode());
					ni_new.setDescription(ni.getDescription());
					ni_new.setSequence(ni.getSequence());
					ni_new.setChargeAdditionalInformation(charge.getChargeAdditionalInformation());
					sm.saveRAD(ni_new);
					charge.getChargeAdditionalInformation().getNoteInformations().add(ni_new);
				}
			}
		}
		Set<UB0481CCLine> ub0481ccLines = null;
		if (oldCharge.getChargeAdditionalInformation() != null) {
			if (oldCharge.getChargeAdditionalInformation().getUb0481CCLines() != null) {
				ub0481ccLines = oldCharge.getChargeAdditionalInformation().getUb0481CCLines();
				charge.getChargeAdditionalInformation().setUb0481CCLines(new HashSet<UB0481CCLine>());
				int i = 0;
				for (UB0481CCLine cc : ub0481ccLines) {
					if (i > 3)
						break;
					UB0481CCLine cc_new = RADBeanFactory.getInstance().createBean(UB0481CCLine.class);
					cc_new.setCode(cc.getCode());
					cc_new.setValue(cc.getValue());
					cc_new.setCodeQualifier(cc.getCodeQualifier());

					cc_new.setSequence(cc.getSequence());

					cc_new.setChargeAdditionalInformation(charge.getChargeAdditionalInformation());
					sm.saveRAD(cc_new);
					charge.getChargeAdditionalInformation().getUb0481CCLines().add(cc_new);
					i++;
				}
			}
		}

		// HCFA
		ChargeAdditionalInformation ca = charge.getChargeAdditionalInformation();
		ChargeAdditionalInformation pmcd = oldCharge.getChargeAdditionalInformation();
		if (pmcd != null) {
			ca.setExcludeFromEMC(pmcd.getExcludeFromEMC());
			ca.setIsPregnant(pmcd.getIsPregnant());
			ca.setDocumentNeeded(pmcd.getDocumentNeeded());
			ca.setAssumedCareDate(pmcd.getAssumedCareDate());
			ca.setRelinquishedCareDate(pmcd.getRelinquishedCareDate());
			ca.setOriginalReferenceNumber(pmcd.getOriginalReferenceNumber());
			ca.setResubmissionCode(pmcd.getResubmissionCode());
			ca.setAllowedAmount(pmcd.getAllowedAmount());
			ca.setDeductibleAmount(pmcd.getDeductibleAmount());
			ca.setCoinsurance(pmcd.getCoinsurance());
			ca.setOutsideLabCharge(pmcd.getOutsideLabCharge());
			ca.setChargeNarrativeData(pmcd.getChargeNarrativeData());
			ca.setIsAutoAccident(pmcd.getIsAutoAccident());
			ca.setIsOtherAccident(pmcd.getIsOtherAccident());
			ca.setIsWorkRelated(pmcd.getIsWorkRelated());
			ca.setIsEmergency(pmcd.getIsEmergency());
			ca.setDisabilityStatus(pmcd.getDisabilityStatus());
			ca.setEpsdtIndicator(pmcd.getEpsdtIndicator());
			ca.setFamiliyPlanningIndicator(pmcd.getFamiliyPlanningIndicator());
			ca.setFamilyPlanningYesNo(pmcd.getFamilyPlanningYesNo());
			ca.setEpsdtIndicator(pmcd.getEpsdtIndicator());
			ca.setEpsdtYesNo(pmcd.getEpsdtYesNo());
			ca.setAutoAccidentState(pmcd.getAutoAccidentState());
			ca.setAccidentDate(pmcd.getAccidentDate());
			ca.setFirstOccurence(pmcd.getFirstOccurence());
			ca.setSimilarSymptoms(pmcd.getSimilarSymptoms());
			ca.setLastSeenByReferring(pmcd.getLastSeenByReferring());
			if (pmcd.getDisabilityInterval() != null) {
				DateInterval di = RADBeanFactory.getInstance().cloneDateInterval(pmcd.getDisabilityInterval());
				sm.saveRAD(di);
				ca.setDisabilityInterval(di);
			}
			if (pmcd.getHospitalizationInterval() != null) {
				DateInterval di = RADBeanFactory.getInstance().cloneDateInterval(pmcd.getHospitalizationInterval());
				sm.saveRAD(di);
				ca.setHospitalizationInterval(di);
			}
			ca.setSpinalManipulationCode(pmcd.getSpinalManipulationCode());
			ca.setAccuteManifestationDate(pmcd.getAccuteManifestationDate());
			ca.setSpinalConditionCode(pmcd.getSpinalConditionCode());
			ca.setLastXRay(pmcd.getLastXRay());
			ca.setPrimaryDocumentControlNumber(pmcd.getPrimaryDocumentControlNumber());
			ca.setSecondaryDocumentControlNumber(pmcd.getSecondaryDocumentControlNumber());
			ca.setTertiaryDocumentControlNumber(pmcd.getTertiaryDocumentControlNumber());
		}
		// ca.setIsPregnant(pmc.getIsPregnant());

		// ca.setAssumedCareDate(pmc.getAssumedCareDate());
		// ca.setRelinquishedCareDate(pmc.getRelinquishedCareDate());

	}

	public static void processTransferToBillingGroup(SessionManager sm, TransferToBgJob job) throws Exception {
		TransferToBillingGroupManager tm = new TransferToBillingGroupManager(sm, job.getModuleDepartment(), job.getChargeId(), job.getBillingGroupId(), job.getBatchId());
		tm.processTransfer();

	}

	protected JournalCode getJournalCode(JournalCodeTransactionKind kind, BillingGroup bg) {
		JournalCode result = null;
		InsurancePlan inp = null;
		BillingGroupInsurance bgi = null;
		try {
			BillingGroup bg1 = sm.get(BillingGroup.class, bg.getId());
			bgi = com.amkai.aes.aescommon.ledger.managers.details.BillingGroupManager.getPrimaryInsurance(bg1);
		} catch (Exception e) {
			log.error(e);
			bgi = null;
		}
		if (bgi != null) {
			inp = bgi.getInsurancePolicy().getInsurancePlan();
		}
		switch (kind) {
		case PAYMENT:
			if (inp != null) {
				result = inp.getDefaultPaymentJournalCode();
			}
			if (result == null) {
				result = getBgs().getPaymentPostJournalCode();
			}
			break;
		case WRITEOFF:
			if (inp != null) {
				result = inp.getDefaultWriteoffJournalCode();
			}
			if (result == null) {
				result = getBgs().getWriteoffPostJournalCode();
			}
			break;
		case DEBIT:
			if (inp != null) {
				result = inp.getDefaultDebitJournalCode();
			}
			if (result == null) {
				result = getBgs().getWriteoffPostJournalCode();
			}
			break;
		default:
			break;
		}

		return result;
	}

	BillingGroupSetup getBgs() {
		if (bgs == null) {
			bgs = TransferToBillingGroupHandler.getBillingGroupSetup(sm, department);
		}
		return bgs;
	}

}
